home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / et / et3_0-a1.lha / et3 / src / GapText.C < prev    next >
C/C++ Source or Header  |  1992-08-26  |  9KB  |  407 lines

  1. #ifdef __GNUG__
  2. #pragma implementation
  3. #endif
  4.  
  5. #include "GapText.h" 
  6.  
  7. #include "Class.h"
  8. #include "RegularExp.h"
  9. #include "Error.h"
  10. #include "Math.h"
  11.  
  12. const int cShrinkFactor = 2,
  13.       cMaxOutput    = 500,
  14.       cInitialSize  = 16;
  15.  
  16. //---- GapText -----------------------------------------------------------------
  17.  
  18. NewMetaImpl(GapText,Text, (T(size), T(length), T(part1len), T(gaplen),
  19.             TV(body, part1len), TV(body2, part2len)));
  20.  
  21. //---- private -----------------------------------------------------------------
  22.  
  23. void GapText::Update(int l)
  24. {
  25.     part1len= l;
  26.     gaplen= size - length;
  27.     part2body= body + gaplen;
  28.     part2len= length - part1len;
  29.     body2= part2body + part1len;
  30. }
  31.  
  32. void GapText::MoveGap(int to)
  33. {
  34.     if (to == part1len)
  35.     return;
  36.     if (part1len > to)
  37.     MemCpy(body+to+gaplen, body+to, part1len-to);
  38.     else 
  39.     MemCpy(body+part1len, body+part1len+gaplen, to-part1len);
  40.  
  41.     part1len= to; 
  42. }            
  43.  
  44. void GapText::CopyTo(byte *dst, int from, int to)
  45.     // Copy Text between 'from' and 'to' to 'dst'
  46.     int beforegap= Math::Max(0, part1len-from) - Math::Max(0, part1len-to);
  47.     int aftergap= Math::Max(0, to - part1len) - Math::Max(0, from-part1len);
  48.  
  49.     if (beforegap) 
  50.     MemCpy(dst, body+from, beforegap);
  51.     if (aftergap)
  52.     MemCpy(dst+beforegap, part2body+Math::Max(part1len, from), aftergap);
  53. }
  54.  
  55. void GapText::Expand(int to, int moveto)
  56.     // Expand size of Text to 'to'
  57.     byte *pos, *part2;
  58.  
  59.     if (to < size) 
  60.     return;
  61.  
  62.     if (moveto > length)
  63.     moveto= length;
  64.  
  65.     size= to;
  66.     pos= new byte[size];
  67.     part2= pos+size-length;
  68.  
  69.     if (moveto < part1len) {
  70.     MemCpy(pos, body, moveto);
  71.     MemCpy(part2+moveto, body+moveto, part1len-moveto);
  72.     MemCpy(part2+part1len, body2, length-part1len);
  73.     } else {
  74.     MemCpy(pos, body, part1len);
  75.     MemCpy(pos+part1len, body2, moveto-part1len);
  76.     MemCpy(part2+moveto, part2body+moveto, length-moveto);
  77.     }
  78.     delete body;
  79.     body= pos;
  80.     Update(moveto);
  81. }
  82.  
  83. void GapText::Shrink(int to)
  84.     byte *pos;
  85.  
  86.     if ((to == 0) || (to < length))
  87.     to= size/cShrinkFactor + 1;
  88.  
  89.     if ( (to > size) || (to < length) ) 
  90.     return;
  91.  
  92.     size= to;
  93.     pos= new byte[size];
  94.     MemCpy(pos, body, part1len);
  95.     MemCpy(pos+part1len, body+part1len+gaplen, part2len);
  96.     delete body;
  97.     body= pos;
  98.     Update(length);
  99. }
  100.  
  101. GapText::GapText(int s, Font *fd)
  102.     size= Math::Max(cInitialSize, s);
  103.     body= new byte[size];
  104.     Init(0, fd);
  105. }
  106.  
  107. GapText::GapText(byte *buf, int len, Font *fd)
  108. {   
  109.     if (len < 0)
  110.     len= strlen((char*)buf);
  111.     size= Math::Max(cInitialSize, len);
  112.     body= new byte[size];
  113.     MemCpy(body, buf, len);
  114.     Init(len, fd);
  115. }
  116.  
  117. void GapText::InitNew()
  118. {
  119.     Text::InitNew();
  120.     Init(0, gSysFont);
  121. }
  122.  
  123. void GapText::Init(int l, Font *fd)
  124. {
  125.     length= l;
  126.     Update(l);
  127.     charStyle= new_CharStyle(fd);
  128.     SetDefTab(fd->Width(' ')*8);
  129.     if (!IsTerminated()) 
  130.     Terminate();
  131. }
  132.  
  133. GapText::~GapText()
  134. {
  135.     SafeDelete(body);
  136.     part2body= 0;
  137. }
  138.  
  139. void GapText::Terminate()
  140. {
  141.     if (IsTerminated())
  142.     return;
  143.     AddChar(Size(), '\0');
  144. }
  145.     
  146. void GapText::AddChar(int at, byte b)
  147. {
  148.     if (HighWaterMark(1))
  149.     Expand(GrowSize(size+1), Size());
  150.     else     
  151.     MoveGap(at);
  152.     body[at]= b;
  153.     length+= 1;
  154.     Update(part1len+1);
  155. }
  156.  
  157. void GapText::ReplaceRange(int from, int to, Text *tsrc, int sfrom, int sto)
  158. {
  159.     GapText *src;
  160.     byte *buf= 0;
  161.  
  162.     if (!CheckRange(End(), from, to))
  163.     Error("ReplaceRange", "out of range");
  164.  
  165.     if (!tsrc->IsKindOf(GapText)) {  // convert the text into a GapText
  166.     int s= sto-sfrom;
  167.     buf= new byte[s+1];
  168.     tsrc->CopyInStr(buf, s+1, sfrom, sto);
  169.     src= new GapText(buf, s);
  170.     sto= sto-sfrom;
  171.     sfrom= 0;
  172.     } else
  173.     src= (GapText *)tsrc;
  174.     
  175.     int shift= (sto - sfrom) - (to - from);
  176.     if (HighWaterMark(shift))
  177.     Expand(GrowSize(size+shift), from);
  178.     else
  179.     MoveGap(from);
  180.  
  181.     src->CopyTo(body+from, sfrom, sto);
  182.  
  183.     length+= shift;
  184.     Update(part1len + (sto-sfrom));
  185.  
  186.     if (LowWaterMark())
  187.     Shrink();   
  188.     if (buf) {
  189.     delete src;
  190.     delete buf;
  191.     }
  192. }
  193.  
  194. void GapText::CopyInStr(byte *str, int strsize, int from, int to)
  195. {
  196.     if (!CheckRange(length, from, to))
  197.     Error("CopyInStr", "out of range");
  198.     to= Math::Min(to, from + strsize-1);   
  199.     CopyTo(str, from, to);
  200.     str[to-from]= '\0';
  201. }
  202.  
  203. Text *GapText::MakeScratchText(byte *buf, int len) 
  204. {
  205.     if (buf)
  206.     return new GapText(buf, len);
  207.     return new GapText(len);
  208. }
  209.  
  210. int GapText::Search(RegularExp *rex, int *nMatched, int start, int range, 
  211.                          bool dir)
  212. {
  213.     int pos;
  214.  
  215.     if (dir == cSearchForward) 
  216.     pos= rex->SearchForward2((char*)body, part1len,
  217.                         (char*)(body+part1len+gaplen), 
  218.             length-part1len, start, range, 0, nMatched);
  219.     else {
  220.     // BUG in RegularExp::SearchBackward2 ??
  221.     MoveGap(length);
  222.     pos= rex->SearchBackward((char*)body, nMatched, start, length, range, 0);
  223.     } 
  224.     return pos;
  225. }
  226.  
  227. byte *GapText::GetLineAccess(byte **buf, int from, int to)
  228. {    
  229.     if (!CheckRange(length, from, to))
  230.     return 0;
  231.  
  232.     if ((part1len < to) && (part1len >= from)) {
  233.     // Gap is in between 
  234.     *buf= (byte*) Realloc(*buf, to-from + 20);
  235.     for (int i= from; i < to; i++)
  236.         (*buf)[i-from]= CharAt(i);
  237.     return *buf;
  238.     }
  239.     if (part1len < from) 
  240.     return &part2body[from];
  241.     return &body[from];
  242. }
  243.  
  244. byte& GapText::operator[](int i)
  245. {
  246.     //----> should notify about possible changes but how?? 
  247.     i= Math::Min(i, length-1);
  248.     if (i < part1len)
  249.     return body[i];
  250.     return part2body[i];
  251. }
  252.  
  253. int GapText::Size()
  254.     return length; 
  255. }                                         
  256.  
  257. TextIter *GapText::MakeIterator(int from, int to)
  258. {
  259.     return new GapTextIter(this, from, to);
  260. }
  261.  
  262. OStream& GapText::PrintOn(OStream& s)
  263. {
  264.     Text::PrintOn(s);
  265.     MoveGap(length);
  266.     return s.PrintString(body, Size());
  267. }
  268.  
  269. IStream& GapText::ReadFrom(IStream& s)
  270. {
  271.     Text::ReadFrom(s);
  272.     SafeDelete(body);
  273.     s.ReadString(&body, &length);
  274.     size= length;
  275.     Update(length);
  276.     return s;
  277. }
  278.  
  279. OStream& GapText::PrintOnAsPureText(OStream& s)
  280. {
  281.     s.write(body, part1len);
  282.     s.write(body2, End() - part1len);
  283.     return s;
  284. }
  285.  
  286. IStream& GapText::ReadFromAsPureText(IStream &s, long sizeHint)
  287. {
  288.     char ch;
  289.  
  290.     if (sizeHint > 0 && ((int)(sizeHint - size)) > 0)
  291.     Expand((int)sizeHint + 50);
  292.     if (body == 0)
  293.     body= new byte[size= 1024];
  294.     length= 0;
  295.     
  296.     while (s.get(ch)) {
  297.     if (length >= size){
  298.         part2body= body ;
  299.         body= new byte[size= (size+1)*2];
  300.         MemCpy(body, part2body, length);
  301.         delete part2body;
  302.     }
  303.     body[length++]= ch;
  304.     }
  305.  
  306.     Update(length);
  307.     Terminate();
  308.     if (!s.eof())
  309.     Error("ReadFromAsPureText", "missing EOF");
  310.     return s;
  311. }
  312.  
  313. //---- GapTextIter -------------------------------------------------------------
  314.  
  315. GapTextIter::GapTextIter(Text *s, int from, int to) : TextIter(s, from, to)
  316. {
  317.     if (!s->IsKindOf(GapText))
  318.     Error("GapTextIter::Error", "GapText expected (%s received)", s->ClassName());
  319.     st= (GapText*)s;
  320.     
  321.     escape= st->GetMarkChar();
  322.     nextFontChange= st->GetNextFontChange(ce, sp);
  323.     if (sp == 0) 
  324.     Error("GapTextIter::GapTextIter", "style is nil");
  325. }
  326.  
  327. void GapTextIter::Reset(Text *s, int from, int to)
  328.     if (!s->IsKindOf(GapText))
  329.     Error("GapTextIter::Reset", "GapTextIter expected (%s received)",
  330.                                 s->ClassName());
  331.     st= (GapText*)s;
  332.  
  333.     TextIter::Reset(s, from, to);
  334.     nextFontChange= st->GetNextFontChange(ce, sp);
  335.     escape= st->GetMarkChar();
  336.     if (sp == 0) 
  337.     Error("GapTextIter::Reset", "style is nil");
  338. }
  339.  
  340. int GapTextIter::GraphicSize(int at, LineDesc *l)
  341. {
  342.     VisualMark *vmp= st->GetVisualMarkAt(at);
  343.     if (l)
  344.     l->Max(vmp->Base(), vmp->GetExtent().y);
  345.     return vmp->GetExtent().x;
  346. }
  347.  
  348. int GapTextIter::operator()(int *w, LineDesc *ld)  
  349. {
  350.     unget= ce;
  351.     if (ce == upto )
  352.     return cEOT;
  353.  
  354.     TestFontChange(sp);
  355.     int ch= CharAt(ce);
  356.     if (TestVisualMark(ce, ch)) {
  357.     if (w)
  358.         *w= GraphicSize(ce, ld);
  359.     }
  360.     else {
  361.     if (w)      
  362.         *w= sp->GetFont()->Width(ch);
  363.     if (ld)
  364.         ld->FromFont(sp->GetFont());
  365.     }
  366.     ce++;
  367.     return ch;
  368. }
  369.  
  370. int GapTextIter::Token(int *w, LineDesc *ld)  
  371. {
  372.     unget= ce;
  373.     *w= 0;
  374.     TestFontChange(sp);
  375.     if (ld) 
  376.     ld->FromFont(sp->GetFont());
  377.     if (ce >= upto)
  378.     return cEOT;
  379.     register int ch= CharAt(ce);
  380.     
  381.     if (TestVisualMark(ce ,ch)) {
  382.     *w= GraphicSize(ce, ld);
  383.     ce++;
  384.     return ch;
  385.     }
  386.     
  387.     if (Iswordwrap(ch)) {
  388.     *w= sp->GetFont()->Width(ch);
  389.     ce++;
  390.     return ch;
  391.     }
  392.     while (ce < upto && !Iswordwrap(CharAt(ce)) && !TestVisualMark(ce, CharAt(ce))) {
  393.     if (TestFontChange(sp) && ld)
  394.         ld->Max(sp->GetFont());
  395.     ch= CharAt(ce++);
  396.     *w+= sp->GetFont()->Width(ch);
  397.     }
  398.     return ch;
  399. }
  400.  
  401.